package qrcode;

public enum Version {

  VERSION_1(1, 21, 202, 31), VERSION_2(2, 25, 235, 31), VERSION_3(3, 29, 243, 31), VERSION_4(4, 33, 251, 31), VERSION_5(
      5, 37, 259, 31), VERSION_6(6, 41, 267, 31), VERSION_7(7, 45, 390, 67), VERSION_8(8, 49, 398, 67), VERSION_9(9,
      053, 406, 67), VERSION_10(10, 57, 404, 67), VERSION_11(11, 61, 422, 67), VERSION_12(12, 65, 430, 67), VERSION_13(
      13, 69, 438, 67), VERSION_14(14, 73, 611, 67), VERSION_15(15, 77, 619, 67), VERSION_16(16, 81, 627, 67), VERSION_17(
      17, 85, 635, 67), VERSION_18(18, 89, 643, 67), VERSION_19(19, 93, 651, 67), VERSION_20(20, 97, 659, 67), VERSION_21(
      21, 101, 882, 67), VERSION_22(22, 105, 890, 67), VERSION_23(23, 109, 898, 67), VERSION_24(24, 113, 906, 67), VERSION_25(
      25, 117, 914, 67), VERSION_26(26, 121, 922, 67), VERSION_27(27, 125, 930, 67), VERSION_28(28, 129, 1203, 67), VERSION_29(
      29, 133, 1211, 67), VERSION_30(30, 137, 1219, 67), VERSION_31(31, 141, 1227, 67), VERSION_32(32, 145, 1235, 67), VERSION_33(
      33, 149, 1243, 67), VERSION_34(34, 153, 1251, 67), VERSION_35(35, 157, 1574, 67), VERSION_36(36, 161, 1582, 67), VERSION_37(
      37, 165, 1590, 67), VERSION_38(38, 169, 1598, 67), VERSION_39(39, 173, 1606, 67), VERSION_40(40, 177, 1614, 67);

  private Integer versionNumber;

  private Version(Integer versionNumber, int numberOfModulesPerSide, int numberOfFunctionPatternModules,
      int numberOfFormatAndVersionInformationModules) {
    this.versionNumber = versionNumber;
    this.numberOfModulesPerSide = numberOfModulesPerSide;
    this.numberOfFunctionPatternModules = numberOfFunctionPatternModules;
    this.numberOfFormatAndVersionInformationModules = numberOfFormatAndVersionInformationModules;
  }

  public Integer getVersionNumber() {
    return versionNumber;
  }

  private int numberOfModulesPerSide;

  private int numberOfFunctionPatternModules;

  private int numberOfFormatAndVersionInformationModules;

  public int getNumberOfDataModules() {
    return numberOfModulesPerSide * numberOfModulesPerSide - numberOfFunctionPatternModules
        - numberOfFormatAndVersionInformationModules;
  }

  public int getNumberOfFormatAndVersionInformationModules() {
    return numberOfFormatAndVersionInformationModules;
  }

  public int getNumberOfFunctionPatternModules() {
    return numberOfFunctionPatternModules;
  }

  public int getNumberOfModulesPerSide() {
    return numberOfModulesPerSide;
  }

  public int getDataCapacity() {
    return getNumberOfDataModules() / 8;
  }

  public int getRemainderBits() {
    return getNumberOfDataModules() % 8;
  }

  public int getNumberOfBitsInCharacterCountIndicator() {
    switch (this) {
    case VERSION_1:
    case VERSION_2:
    case VERSION_3:
    case VERSION_4:
    case VERSION_5:
    case VERSION_6:
    case VERSION_7:
    case VERSION_8:
    case VERSION_9:
      return 10;
    case VERSION_10:
    case VERSION_11:
    case VERSION_12:
    case VERSION_13:
    case VERSION_14:
    case VERSION_15:
    case VERSION_16:
    case VERSION_17:
    case VERSION_18:
    case VERSION_19:
    case VERSION_20:
    case VERSION_21:
    case VERSION_22:
    case VERSION_23:
    case VERSION_24:
    case VERSION_25:
    case VERSION_26:
      return 12;
    case VERSION_27:
    case VERSION_28:
    case VERSION_29:
    case VERSION_30:
    case VERSION_31:
    case VERSION_32:
    case VERSION_33:
    case VERSION_34:
    case VERSION_35:
    case VERSION_36:
    case VERSION_37:
    case VERSION_38:
    case VERSION_39:
    case VERSION_40:
      return 14;
    }
    throw new IllegalStateException("Version " + this + " not implemented yet.");
  }

  public int[] getAlignmentPatternCenters() {
    switch (this) {
    case VERSION_1:
      return new int[] {};
    case VERSION_2:
      return new int[] { 6, 18 };
    case VERSION_3:
      return new int[] { 6, 22 };
    case VERSION_4:
      return new int[] { 6, 26 };
    case VERSION_5:
      return new int[] { 6, 30 };
    case VERSION_6:
      return new int[] { 6, 34 };
    case VERSION_7:
      return new int[] { 6, 22, 38 };
    case VERSION_8:
      return new int[] { 6, 24, 42 };
    case VERSION_9:
      return new int[] { 6, 26, 46 };
    case VERSION_10:
      return new int[] { 6, 28, 50 };
    case VERSION_11:
      return new int[] { 6, 30, 54 };
    case VERSION_12:
      return new int[] { 6, 32, 58 };
    case VERSION_13:
      return new int[] { 6, 34, 62 };
    case VERSION_14:
      return new int[] { 6, 46, 66 };
    case VERSION_15:
      return new int[] { 6, 48, 70 };
    case VERSION_16:
      return new int[] { 6, 50, 74 };
    case VERSION_17:
      return new int[] { 6, 54, 78 };
    case VERSION_18:
      return new int[] { 6, 56, 82 };
    case VERSION_19:
      return new int[] { 6, 58, 86 };
    case VERSION_20:
      return new int[] { 6, 62, 90 };
    case VERSION_21:
      return new int[] { 6, 50, 72, 94 };
    case VERSION_22:
      return new int[] { 6, 50, 74, 98 };
    case VERSION_23:
      return new int[] { 6, 54, 78, 105 };
    case VERSION_24:
      return new int[] { 6, 54, 80, 106 };
    case VERSION_25:
      return new int[] { 6, 32, 58, 84, 110 };
    case VERSION_26:
      return new int[] { 6, 30, 58, 86, 114 };
    case VERSION_27:
      return new int[] { 6, 34, 62, 90, 118 };
    case VERSION_28:
      return new int[] { 6, 26, 50, 74, 98, 122 };
    case VERSION_29:
      return new int[] { 6, 30, 54, 78, 102, 126 };
    case VERSION_30:
      return new int[] { 6, 26, 52, 78, 104, 130 };
    case VERSION_31:
      return new int[] { 6, 30, 56, 82, 108, 134 };
    case VERSION_32:
      return new int[] { 6, 34, 60, 86, 112, 138 };
    case VERSION_33:
      return new int[] { 6, 30, 58, 86, 114, 142 };
    case VERSION_34:
      return new int[] { 6, 34, 62, 90, 118, 146 };
    case VERSION_35:
      return new int[] { 6, 30, 54, 78, 102, 126 };
    case VERSION_36:
      return new int[] { 6, 24, 50, 76, 102, 128, 154 };
    case VERSION_37:
      return new int[] { 6, 28, 54, 80, 106, 132, 158 };
    case VERSION_38:
      return new int[] { 6, 32, 58, 84, 110, 136, 162 };
    case VERSION_39:
      return new int[] { 6, 26, 54, 82, 110, 138, 166 };
    case VERSION_40:
      return new int[] { 6, 30, 58, 86, 114, 142, 170 };
    }
    throw new IllegalStateException("Version " + this + " not implemented yet.");
  }

  public boolean hasVersionInformation() {
    return versionNumber != null && versionNumber.intValue() > 6;
  }
  
  public int getVersionInformationBits(){
    switch (this){
    case VERSION_7:
      return 0x07C94;
    case VERSION_8:
      return 0x085BC;
    case VERSION_9:
      return 0x09A99;
    case VERSION_10:
      return 0x0A4D3;
    case VERSION_11:
      return 0x0BBF6;
    case VERSION_12:
      return 0x0C762;
    case VERSION_13:
      return 0x0D847;
    case VERSION_14:
      return 0x0E60D;
    case VERSION_15:
      return 0x0F928;
    case VERSION_16:
      return 0x10B78;
    case VERSION_17:
      return 0x1145D;
    case VERSION_18:
      return 0x12A17;
    case VERSION_19:
      return 0x13532;
    case VERSION_20:
      return 0x149A6;
    case VERSION_21:
      return 0x15683;
    case VERSION_22:
      return 0x168C9;
    case VERSION_23:
      return 0x177EC;
    case VERSION_24:
      return 0x18EC4;
    case VERSION_25:
      return 0x191E1;
    case VERSION_26:
      return 0x1AFAB;
    case VERSION_27:
      return 0x1B08E;
    case VERSION_28:
      return 0x1CC1A;
    case VERSION_29:
      return 0x1D33F;
    case VERSION_30:
      return 0x1ED75;
    case VERSION_31:
      return 0x1F250;
    case VERSION_32:
      return 0x209D5;
    case VERSION_33:
      return 0x216F0;
    case VERSION_34:
      return 0x228BA;
    case VERSION_35:
      return 0x2379F;
    case VERSION_36:
      return 0x24B0B;
    case VERSION_37:
      return 0x2542E;
    case VERSION_38:
      return 0x26A64;
    case VERSION_39:
      return 0x27541;
    case VERSION_40:
      return 0x28C69;
      default: throw new IllegalStateException("Version " + this + " has no version information bits.");
    }
  }
}